package net.kazed.nextaction.task;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.kazed.android.inject.Autowired;
import net.kazed.android.inject.InjectedActivity;
import net.kazed.nextaction.ApplicationResource;
import net.kazed.nextaction.NextActionApplication;
import net.kazed.nextaction.R;
import net.kazed.nextaction.context.activity.ContextView2Activity;
import net.kazed.nextaction.context.activity.ContextsActivity;
import net.kazed.nextaction.database.ContextCache;
import net.kazed.nextaction.database.GtdContext;
import net.kazed.nextaction.database.Task;
import net.kazed.nextaction.database.TaskContext;
import net.kazed.nextaction.database.TaskDao;
import net.kazed.nextaction.database.TaskStatus;
import net.kazed.nextaction.database.TreeNode;
import net.kazed.nextaction.task.context.TaskContextList;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;

/**
 * Activity to edit a Task.
 * @author Koert Zeilstra
 */
public class TaskEditorActivity extends InjectedActivity {

    private static final String PARAM_NEW_TASK_CONTEXTS = "newTaskContexts";

   private static final String PARAM_DELETED_TASK_CONTEXTS = "deletedTaskContexts";

   private static final String PARAM_TASK_CONTEXTS = "taskContexts";

   private static final int DEFAULT_CONTEXT_ID = 0;
   private static final int DEFAULT_TASK_ID = 0;

   private static final String TAG = "TaskEditorActivity";
    
    private static final int MENU_REVERT = Menu.FIRST;
    private static final int MENU_DELETE = Menu.FIRST + 1;
    private static final int MENU_INSERT_ATTACHMENT = MENU_DELETE + 1;
    private static final int START_DATE_DIALOG = 0;
    private static final int DUE_DATE_DIALOG = 1;
    private static final int ADD_ATTACHMENT_DIALOG = 2;
    private static final int ADD_ATTACHMENT_DIALOG2 = 3;
    private static final int TASK_CONTEXT_SELECTOR = 5;
    
    private static final int PICK_PARENT = 1;

    private ContextCache contextCache;
    private TaskAttachmentManager taskAttachmentManager;
    private TaskDao taskDao;
    
    private String action;
    private Cursor cursor;
    private boolean isNew;
    private Uri itemUri;
    private int selectedContextId;
    private Integer parentTaskId;
    private Task originalTask;
    private TaskContextList taskContexts;
    private TaskContextList newTaskContexts;
    private TaskContextList deletedTaskContexts;
    private Task parentTask;
//    private List<GtdContext> contextList;
    private ApplicationResource applicationResource;
    private Map<Integer, TaskStatus> positionToTypeMap;
    private Map<TaskStatus, Integer> typeToPositionMap;
    private ListAdapter listAdapter;
    private AlertDialog alertDialog;
    private int selectedAttachmentTypeIndex;

    private RelativeLayout parentGroup;
    private TextView parentDescription;
    private Button parentChoose;
    private EditText nameWidget;
    private LinearLayout taskContextContainer;
    private LinearLayout taskContextList;
    private ImageButton taskContextButton;
    private Spinner typeSpinner;
    private CheckBox completedWidget;
    private DateInput startDateInput;
    private DateInput dueDateInput;
    private EditText noteWidget;
    private Button saveButton;
    private Button cancelButton;
    private SpecialAction onResumeAction;

    @Autowired
    public void setContextCache(ContextCache contextCache) {
      this.contextCache = contextCache;
   }

    @Autowired
    public void setTaskAttachmentManager(TaskAttachmentManager taskAttachmentManager) {
      this.taskAttachmentManager = taskAttachmentManager;
   }

   @Autowired
   public void setTaskDao(TaskDao taskDao) {
      this.taskDao = taskDao;
   }

   @Override
   public void onCreate(Bundle icicle) {
         Log.d(TAG, "onCreate+");
        super.onCreate(icicle);
        
        Resources resources = getResources();
        
        final Intent intent = getIntent();
        action = intent.getAction();
        selectedContextId = intent.getIntExtra(GtdContext.SELECTED_CONTEXT_ID, DEFAULT_CONTEXT_ID);
        parentTaskId = intent.getIntExtra(Task.SELECTED_PARENT_ID, DEFAULT_TASK_ID);
        if (parentTaskId == DEFAULT_TASK_ID) {
           parentTaskId = null;
        }
        taskContexts = new TaskContextList();
        newTaskContexts = new TaskContextList();
        deletedTaskContexts = new TaskContextList();
        if (action.equals(Intent.ACTION_EDIT)) {
            isNew = false;
            itemUri = intent.getData();
            setResult(RESULT_OK, intent);
            cursor = managedQuery(itemUri, Task.FULL_PROJECTION.getFieldNames(), null, null, null);
            if (cursor == null) {
               throw new IllegalArgumentException("task not found: " + itemUri);
            }
        } else if (action.equals(Intent.ACTION_INSERT)) {
           isNew = true;
           itemUri = intent.getData();
           if (itemUri == null) {
              Log.e(TAG, "Failed to insert new item into " + getIntent().getData());
              finish();
              return;
           }
           // KZ - put this in onSaveInstanceState or onPause ?
          Bundle bundle = new Bundle();
          bundle.putString(ContextsActivity.SELECTED_ITEM, itemUri.toString());
          Intent mIntent = new Intent(Intent.ACTION_EDIT, itemUri);
          mIntent.putExtras(bundle);
          setResult(RESULT_OK, mIntent);
        } else {
            finish();
            return;
        }

        setContentView(R.layout.task_editor);
        parentGroup = (RelativeLayout) findViewById(R.id.parent_group);
        parentDescription = (TextView) findViewById(R.id.parent_description);
        parentChoose = (Button) findViewById(R.id.task_parent_choose_button);
        parentChoose.setOnClickListener(new ParentChooseOnClickListener());
        nameWidget = (EditText) findViewById(R.id.description);
        taskContextContainer = (LinearLayout) findViewById(R.id.task_context_container);
        taskContextContainer.setOnClickListener(new TaskContextContainerOnClickListener());
        taskContextList = (LinearLayout) findViewById(R.id.task_contexts);
        taskContextButton = (ImageButton) findViewById(R.id.task_contexts_button);
        taskContextButton.setOnClickListener(new TaskContextContainerOnClickListener());
        typeSpinner = (Spinner) findViewById(R.id.task_type_spinner);
        completedWidget = (CheckBox) findViewById(R.id.completed_checkbox);
        
        startDateInput = new DateInput(this, R.id.start_date_display, R.id.start_date_set_button, R.id.start_date_clear_button,
                        START_DATE_DIALOG);
        dueDateInput = new DateInput(this, R.id.due_date_display, R.id.due_date_set_button, R.id.due_date_clear_button,
                        DUE_DATE_DIALOG);
        noteWidget = (EditText) findViewById(R.id.notes);
        
        saveButton = (Button) findViewById(R.id.save_button);
        saveButton.setOnClickListener(new SaveOnClickListener());
        
        cancelButton = (Button) findViewById(R.id.cancel_button);
        cancelButton.setOnClickListener(new CancelOnClickListener());
        
        if (action.equals(Intent.ACTION_EDIT)) {
            parentGroup.setVisibility(View.VISIBLE);
        } else {
            parentGroup.setVisibility(View.GONE);
        }

        NextActionApplication application = (NextActionApplication) getApplication();
        applicationResource = application.getApplicationResource();
        
        positionToTypeMap = new HashMap<Integer, TaskStatus>();
        typeToPositionMap = new HashMap<TaskStatus, Integer>();
        List<TaskStatus> actionTypes = applicationResource.getActionTypes();
        String[] taskTypes = new String[actionTypes.size()];
        int taskIndex = 0;
        for (TaskStatus type : actionTypes) {
            taskTypes[taskIndex] = resources.getString(applicationResource.getTaskTypeName(type));
            positionToTypeMap.put(taskIndex, type);
            typeToPositionMap.put(type, taskIndex);
            taskIndex++;
        }
        ArrayAdapter<String> typeAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
                        android.R.id.text1, taskTypes);
        typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        typeSpinner.setAdapter(typeAdapter);
                  
//        List<GtdContext> contextsFromTree = contextCache.getFlattenedContextTree();
//        contextList = new ArrayList<GtdContext>(contextsFromTree.size() + 1);
//        String inboxTitle = getResources().getString(R.string.inbox_title);
//        GtdContext inboxContext = new GtdContext(inboxTitle);
//        contextList.add(inboxContext);
//        contextList.addAll(contextCache.getFlattenedContextTree());

        if (isNew) {
           setTitle(R.string.title_new_task);
           originalTask = new Task();
           originalTask.setParentTaskId(parentTaskId);
           if (selectedContextId != DEFAULT_CONTEXT_ID) {
              taskContexts.add(new TaskContext(-1, selectedContextId));
           }
        } else {
           setTitle(R.string.title_edit_task);
           cursor.moveToFirst();
           originalTask = new Task(cursor);
           parentTaskId = originalTask.getParentTaskId();
           taskContexts.addAll(taskDao.getTaskContexts(originalTask.getId()));
        }
        if (parentTaskId != null) {
           Uri parentItem = ContentUris.withAppendedId(Task.CONTENT_URI, parentTaskId);
           Cursor parentCursor = managedQuery(parentItem, Task.FULL_PROJECTION.getFieldNames(), null, null, null);
           if (parentCursor.moveToFirst()) {
              parentTask = new Task(parentCursor);
           }
           parentCursor.close();
        }
        populateFields(originalTask);
        if (icicle != null) {
           taskContexts = icicle.getParcelable(PARAM_TASK_CONTEXTS);
           deletedTaskContexts = icicle.getParcelable(PARAM_DELETED_TASK_CONTEXTS);
           newTaskContexts = icicle.getParcelable(PARAM_NEW_TASK_CONTEXTS);
        }

        nameWidget.selectAll();
    }
    
    @Override
    protected void onResume() {
        Log.d(TAG, "onResume+");
        super.onResume();

        if (onResumeAction != null) {
            onResumeAction.execute();
        }
    }

   private void populateFields(Task task) {
       if (parentTask == null) {
           parentChoose.setText(R.string.task_parent_choose_button_title);
           parentDescription.setText(R.string.project_none);
       } else {
           parentChoose.setText(R.string.task_parent_detach_button_title);
           parentDescription.setText(parentTask.getDescription());
       }

       if (!isNew) {
          nameWidget.setTextKeepState(task.getDescription() == null ? "" : task.getDescription());
          completedWidget.setChecked(task.getComplete());
          startDateInput.setDate(task.getStartDate());
          dueDateInput.setDate(task.getDueDate());
          noteWidget.setTextKeepState(task.getDetails());
          
          TaskStatus type = task.getStatus(TaskStatus.UNPROCESSED);
          typeSpinner.setSelection(typeToPositionMap.get(type));
       }
      
      populateContextList();
   }

   private void populateContextList() {
      taskContextList.removeAllViews();
      LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      if (taskContexts.isEmpty()) {
         View contextView = vi.inflate(R.layout.task_context_list_item_view, taskContextList, false); 
         TextView contextNameView = (TextView) contextView.findViewById(R.id.name);
         contextNameView.setText(R.string.no_contexts_in_view);
         taskContextList.addView(contextView);
      } else {
         for (final TaskContext taskContext : taskContexts) {
            TreeNode<GtdContext> treeNode = contextCache.getContextTree(taskContext.getContextId());
            ContextCache.ContextPathBuilder pathBuilder = new ContextCache.ContextPathBuilder("/");
            treeNode.fillContextPath(pathBuilder);
//            TextView contextNameView = new TextView(this);
//            contextNameView.setText(pathBuilder.getPath());
//            taskContextContainer.addView(contextNameView);
            View contextView = vi.inflate(R.layout.task_context_list_item_view, taskContextList, false); 
            TextView contextNameView = (TextView) contextView.findViewById(R.id.name);
            contextNameView.setText(pathBuilder.getPath());
            taskContextList.addView(contextView);
         }
      }
      taskContextContainer.requestLayout();
   }
    
   @Override
   protected Dialog onCreateDialog(int id) {
       Dialog dialog = null;
       switch (id) {
       case START_DATE_DIALOG:
           dialog = startDateInput.createDialog();
           break;
       case DUE_DATE_DIALOG:
           dialog = dueDateInput.createDialog();
           break;
       case ADD_ATTACHMENT_DIALOG:
           listAdapter = taskAttachmentManager.getAttachmentTypeListAdapter(getApplicationContext(),
                           android.R.layout.select_dialog_singlechoice);
           alertDialog = new AlertDialog.Builder(this)
//               .setIcon(android.R.drawable.alert_dialog_icon)
               .setTitle(R.string.add_attachment_dialog_title)
               .setSingleChoiceItems(listAdapter, selectedAttachmentTypeIndex, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       selectedAttachmentTypeIndex = whichItem;
                   }
               })
               .setPositiveButton(R.string.ok_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       AttachmentType attachmentType = taskAttachmentManager.getActiveAttachmentType(selectedAttachmentTypeIndex);
                       Intent intent = attachmentType.getIntent();
                       startActivityForResult(intent, attachmentType.getRequestCode());
                   }
               })
               .setNegativeButton(R.string.cancel_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       /* User clicked No so do some stuff */
                   }
               })
              .create();
               dialog = alertDialog;
               break;
       case ADD_ATTACHMENT_DIALOG2:
           listAdapter = taskAttachmentManager.getAttachmentTypeListAdapter(getApplicationContext(),
                           android.R.layout.select_dialog_singlechoice);
           alertDialog = new AlertDialog.Builder(this)
               .setTitle(R.string.add_attachment_dialog_title)
               .setSingleChoiceItems(listAdapter, selectedAttachmentTypeIndex, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       selectedAttachmentTypeIndex = whichItem;
                   }
               })
               .setPositiveButton(R.string.ok_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       AttachmentType attachmentType = taskAttachmentManager.getActiveAttachmentType(selectedAttachmentTypeIndex);
                       Intent intent = attachmentType.getIntent();
                       startActivityForResult(intent, attachmentType.getRequestCode());
                   }
               })
               .setNegativeButton(R.string.cancel_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       /* User clicked No so do some stuff */
                   }
               })
              .create();
               dialog = alertDialog;
               break;
       }
       
       return dialog;
   }

   @Override
   protected void onPrepareDialog(int id, Dialog dialog) {
       switch (id) {
       case START_DATE_DIALOG:
           startDateInput.updateDialog(dialog);
           break;
       case DUE_DATE_DIALOG:
           dueDateInput.updateDialog(dialog);
           break;
       }
   }

    @Override
	protected void onActivityResult(int requestCode, int resultCode,
			Intent data) {

        if (resultCode == RESULT_OK) {
            switch (requestCode) {
            case PICK_PARENT:
                Uri uri = data.getData();
                int parentTaskId = (int) ContentUris.parseId(uri);
                originalTask.setParentTaskId(parentTaskId);
                updateTask(originalTask);
                break;
            case TASK_CONTEXT_SELECTOR:
               taskContexts = data.getParcelableExtra(PARAM_TASK_CONTEXTS);
               deletedTaskContexts = data.getParcelableExtra(PARAM_DELETED_TASK_CONTEXTS);
               newTaskContexts = data.getParcelableExtra(PARAM_NEW_TASK_CONTEXTS);
               populateContextList();
               break;
            default:
                AttachmentType type = taskAttachmentManager.getAttachmentTypeByRequestCode(requestCode);
                if (type != null) {
                    String link = type.getAttachmentLink(this, data);
                    String noteText = noteWidget.getText().toString();
                    int start = noteWidget.getSelectionStart();
                    if (start < 0) {
                        noteText = noteText + link;
                    } else {
                        noteText = noteText.substring(0, start) + link + noteText.substring(start);
                    }
                    final String t = noteText;
                    onResumeAction = new SpecialAction() {
                        public void execute() {
                            noteWidget.setTextKeepState(t);
                            onResumeAction = null;
                        }
                    };
                }
            }
        }
	}

    /**
     * Update task in database.
     * @param task Task.
     */
    private void updateTask(Task task) {
        ContentValues values = new ContentValues();
        task.toValues(values);
        getContentResolver().update(itemUri, values, null, null);
    }
    
    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
   protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      outState.putParcelable(PARAM_TASK_CONTEXTS, taskContexts);
      outState.putParcelable(PARAM_DELETED_TASK_CONTEXTS, deletedTaskContexts);
      outState.putParcelable(PARAM_NEW_TASK_CONTEXTS, newTaskContexts);
   }

   /**
     * Save current task.
     */
   private void saveTask() {
      Task task = originalTask;
      if (isNew) {
         task.setContextId((int) selectedContextId);
      }
      task.setDescription(nameWidget.getText().toString());
      TaskStatus type = positionToTypeMap.get(typeSpinner.getSelectedItemPosition());
      if (type == null) {
          type = TaskStatus.UNPROCESSED;
      }
      task.setStatus(type);
      task.setComplete(completedWidget.isChecked());
      task.setDetails(noteWidget.getText().toString());
//      int contextPosition = contextSpinner.getSelectedItemPosition();
//      if (contextPosition < contextList.size()) {
//         GtdContext context = contextList.get(contextPosition);
//         task.setContextId(context.getId());
//      }
      if (taskContexts.isEmpty()) {
         task.setContextId(0);
      } else {
         task.setContextId(1);
      }
      task.setStartDate(startDateInput.getDate());
      task.setDueDate(dueDateInput.getDate());
      ContentValues values = new ContentValues();
      task.toValues(values);
      if (isNew) {
         itemUri = getContentResolver().insert(itemUri, values);
         int taskId = Integer.parseInt(itemUri.getLastPathSegment());
         for (TaskContext taskContext : taskContexts) {
            newTaskContexts.add(new TaskContext(taskId, taskContext.getContextId()));
         }
         taskContexts = newTaskContexts;
      } else {
         getContentResolver().update(itemUri, values, null, null);
      }
      for (TaskContext taskContext: deletedTaskContexts) {
         taskDao.delete(taskContext);
      }
      deletedTaskContexts.clear();
      for (TaskContext taskContext: newTaskContexts) {
         taskDao.save(taskContext);
      }
      newTaskContexts.clear();
   }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       Resources resources = getResources();
       int order = 0;
       if (noteWidget.isFocused()) {
           menu.add(0, MENU_INSERT_ATTACHMENT, order++, resources.getString(R.string.menu_add_attachment))
           .setIcon(android.R.drawable.ic_menu_add).setAlphabeticShortcut('i');
       }
       menu.add(0, MENU_REVERT, order++, resources.getString(R.string.menu_revert))
          .setIcon(android.R.drawable.ic_menu_revert).setAlphabeticShortcut('r');
       menu.add(0, MENU_DELETE, order++, resources.getString(R.string.menu_delete))
          .setIcon(android.R.drawable.ic_menu_delete).setAlphabeticShortcut('d');
       return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       switch (item.getItemId()) {
       case MENU_INSERT_ATTACHMENT:
           showDialog(ADD_ATTACHMENT_DIALOG);
           break;
       case MENU_REVERT:
           populateFields(originalTask);
           break;
       case MENU_DELETE:
           AlertDialog.Builder builder = new AlertDialog.Builder(TaskEditorActivity.this);
           builder.setTitle(R.string.task_delete_alert_title).setMessage(R.string.task_delete_alert_message)
               .setIcon(android.R.drawable.ic_dialog_alert);
           builder.setPositiveButton(R.string.alert_yes, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int whichButton) {
                   getContentResolver().delete(itemUri, null, null);
                   finish();
               }
           });
           builder.setNegativeButton(R.string.alert_no, null);
           builder.show();
           break;
       }
       return super.onOptionsItemSelected(item);
    }
    
    /**
     * Take care of deleting a context.  Simply deletes the entry.
     */
    protected void deleteItem() {
       nameWidget.setText("");
    }

   private class CancelOnClickListener implements View.OnClickListener {
      @Override
      public void onClick(View v) {
         setResult(RESULT_CANCELED);
         finish();
      }
   }

   private class SaveOnClickListener implements View.OnClickListener {
      @Override
      public void onClick(View v) {
         saveTask();
         Intent resultIntent = new Intent(action, itemUri);
         setResult(RESULT_OK, resultIntent);
         finish();
      }
   }

   private class ParentChooseOnClickListener implements View.OnClickListener {
      @Override
      public void onClick(View v) {
         if (parentTask == null) {
            Intent intent = new Intent(ContextView2Activity.PICK_TASK, GtdContext.CONTENT_URI);
            startActivityForResult(intent, PICK_PARENT);
         } else {
            parentTask = null;
            originalTask.setParentTaskId(null);
            updateTask(originalTask);
            populateFields(originalTask);
         }
      }
   }

   private final class TaskContextContainerOnClickListener implements View.OnClickListener {
      @Override
      public void onClick(View v) {
         Intent intent = new Intent(TaskEditorActivity.this, TaskContextSelectorActivity.class);
         intent.putExtra("taskId", originalTask.getId());
         intent.putExtra(PARAM_TASK_CONTEXTS, taskContexts);
         intent.putExtra(PARAM_DELETED_TASK_CONTEXTS, deletedTaskContexts);
         intent.putExtra(PARAM_NEW_TASK_CONTEXTS, newTaskContexts);
         startActivityForResult(intent, TASK_CONTEXT_SELECTOR);
      }
   }

    private interface SpecialAction {
        void execute();
    }
    
}
